package com.yugao.fintech.antelope.pay.common.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yugao.fintech.antelope.base.config.GlobalProperties;
import com.yugao.fintech.antelope.base.exception.enums.GlobalErrorEnum;
import com.yugao.fintech.antelope.base.security.utils.SecurityUtils;
import com.yugao.fintech.antelope.base.model.module.auth.LoginUser;
import com.yugao.fintech.antelope.pay.common.assembly.PayInterfaceAssembly;
import com.yugao.fintech.antelope.pay.common.constants.Cs;
import com.yugao.fintech.antelope.pay.common.manager.MchInfoManager;
import com.yugao.fintech.antelope.pay.common.manager.MchPayPassageManager;
import com.yugao.fintech.antelope.pay.common.manager.PayInterfaceDefineManager;
import com.yugao.fintech.antelope.pay.common.manager.PayMqSender;
import com.yugao.fintech.antelope.pay.common.mapper.PayInterfaceConfigMapper;
import com.yugao.fintech.antelope.pay.common.model.mq.ResetIsvMchAppInfoConfigMQ;
import com.yugao.fintech.antelope.pay.common.service.MchAppService;
import com.yugao.fintech.antelope.pay.common.service.PayInterfaceConfigService;
import com.yugao.fintech.antelope.pay.constant.IfCodeEnum;
import com.yugao.fintech.antelope.pay.constant.PayErrorEnum;
import com.yugao.fintech.antelope.pay.model.rqrs.PayConfigQL;
import com.yugao.fintech.antelope.pay.model.rqrs.PayInterfaceConfigRQ;
import com.yugao.fintech.antelope.pay.model.rqrs.PayInterfaceConfigRS;
import com.yugao.fintech.antelope.pay.model.rqrs.PayInterfaceRQ;
import com.yugao.fintech.antelope.pay.payment.factory.AbstractPayFactory;
import com.yugao.fintech.antelope.pay.payment.model.params.NormalMchParams;
import com.yugao.fintech.framework.assistant.utils.StringUtils;
import com.yugao.fintech.framework.assistant.utils.exception.BizException;
import com.yugao.fintech.framework.assistant.crypto.AesCrypto;
import com.yugao.fintech.framework.desensitization.annotations.FieldBindHandle;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;


@Service
public class PayInterfaceConfigServiceImpl extends ServiceImpl<PayInterfaceConfigMapper, PayInterfaceConfig>
        implements PayInterfaceConfigService {
    @Autowired
    private PayInterfaceAssembly payInterfaceAssembly;
    @Autowired
    private MchAppService mchAppService;
    @Autowired
    private MchPayPassageManager mchPayPassageManager;
    @Autowired
    private MchInfoManager mchInfoManager;
    @Autowired
    private PayInterfaceDefineManager payInterfaceDefineManager;
    @Autowired
    private GlobalProperties globalProperties;
    @Autowired
    private PayMqSender payMqSender;

    @Override
    @FieldBindHandle
    public List<PayInterfaceConfigRS> listPayIfConfig(PayConfigQL query) {
        MchApp mchApp = mchAppService.getById(query.getAppId());
        if (Objects.isNull(mchApp)) {
            throw new BizException(PayErrorEnum.MCH_APP_NOT_EXIST);
        }
        MchInfo mchInfo = mchInfoManager.getById(mchApp.getMchNo());
        if (Objects.isNull(mchInfo)) {
            throw new BizException(PayErrorEnum.MCH_NOT_EXIST);
        }

        Map<String, PayInterfaceConfig> isvPayConfigMap = new HashMap<>(); // 服务商支付参数配置集合

        // 支付定义列表
        LambdaQueryWrapper<PayInterfaceDefine> lqw = PayInterfaceDefine.lqw()
                .eq(PayInterfaceDefine::getStatus, Cs.YES)
                // 根据商户类型，添加接口是否支持该商户类型条件 - 支持普通商户模式
                .eq(Cs.MCH_TYPE_NORMAL.equals(mchInfo.getType()), PayInterfaceDefine::getIsMchMode, Cs.YES);

        if (Cs.MCH_TYPE_ISVSUB.equals(mchInfo.getType())) {
            // 支持服务商模式
            lqw.eq(PayInterfaceDefine::getIsIsvMode, Cs.YES);
            // 商户类型为特约商户，服务商应已经配置支付参数
            List<PayInterfaceConfig> isvConfigList = this.list(PayInterfaceConfig.lqw()
                    .eq(PayInterfaceConfig::getInfoId, mchInfo.getIsvNo())
                    .eq(PayInterfaceConfig::getInfoType, Cs.INFO_TYPE_ISV)
                    .eq(PayInterfaceConfig::getStatus, Cs.YES)
                    .ne(PayInterfaceConfig::getIfParams, "")
                    .isNotNull(PayInterfaceConfig::getIfParams));
            for (PayInterfaceConfig config : isvConfigList) {
                config.addExt("mchType", mchInfo.getType());
                isvPayConfigMap.put(config.getIfCode(), config);
            }
        }

        Map<String, List<PayInterfaceDefine>> defineMap = payInterfaceDefineManager.list(lqw).stream()
                .collect(Collectors.groupingBy(PayInterfaceDefine::getIfCode));
        // 支付参数列表
        LambdaQueryWrapper<PayInterfaceConfig> wrapper = PayInterfaceConfig.lqw()
                .eq(PayInterfaceConfig::getInfoId, query.getAppId())
                .like(StringUtils.isNotEmpty(query.getIfCode()), PayInterfaceConfig::getIfCode, query.getIfCode())
                .eq(StringUtils.isNotEmpty(query.getStatus()), PayInterfaceConfig::getStatus, query.getStatus())
                .eq(PayInterfaceConfig::getInfoType, Cs.INFO_TYPE_MCH_APP);
        List<PayInterfaceConfig> configList = this.list(wrapper);

        List<PayInterfaceConfigRS> configRespList = configList.stream()
                .map(payInterfaceAssembly::toPayInterfaceConfigResp)
                .collect(Collectors.toList());

        AesCrypto aesCrypto = new AesCrypto(globalProperties.getSecretKey());
        configRespList.forEach(config -> {
            // 所属商户类型
            config.setMchType(mchInfo.getType());
            config.setIfParams(aesCrypto.decrypt(config.getIfParams()));
            if (Cs.MCH_TYPE_ISVSUB.equals(mchInfo.getType()) && isvPayConfigMap.get(config.getIfCode()) == null) {
                // 特约商户，服务商支付参数的配置状态，0表示未配置
                config.setSubMchIsvConfig(Cs.NO);
            }
            defineMap.get(config.getIfCode()).stream().findFirst().ifPresent(e -> {
                String mchParams = Cs.MCH_TYPE_NORMAL.equals(mchInfo.getType()) ? e.getNormalMchParams() : e.getIsvsubMchParams();
                config.setMchParams(mchParams);
                config.setIfName(e.getIfName());
                config.setIsMchMode(e.getIsMchMode());
                config.setIsIsvMode(e.getIsIsvMode());
                config.setConfigPageType(e.getConfigPageType());
            });
        });
        return configRespList;
    }

    @Override
    public void updatePayIfConfig(PayInterfaceConfigRQ req) {
        PayInterfaceConfig dbRecord = this.getById(req.getId());
        if (Objects.isNull(dbRecord)) {
            throw new BizException(GlobalErrorEnum.OPERATION_FAIL_SELETE);
        }
        AesCrypto aesCrypto = new AesCrypto(globalProperties.getSecretKey());
        PayInterfaceConfig payInterfaceConfig = payInterfaceAssembly.toPayInterfaceConfig(req);

        // 存入真实费率
        if (payInterfaceConfig.getIfRate() != null) {
            payInterfaceConfig.setIfRate(payInterfaceConfig.getIfRate().divide(new BigDecimal("100"), 6, RoundingMode.HALF_UP));
        }

        // 添加更新者信息
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Long userId = loginUser.getUserId();
        String realName = loginUser.getUserName();
        payInterfaceConfig.setUpdatedUid(userId);
        payInterfaceConfig.setUpdatedBy(realName);

        // 合并支付参数
//        String ifParams = aesCrypto.encrypt(StringKit.marge(aesCrypto.decrypt(dbRecord.getIfParams()), payInterfaceConfig.getIfParams()));
        payInterfaceConfig.setIfParams(aesCrypto.encrypt(payInterfaceConfig.getIfParams()));
        boolean result = this.saveOrUpdate(payInterfaceConfig);
        if (!result) {
            throw new BizException("配置失败");
        }

        // 推送修改消息
        ResetIsvMchAppInfoConfigMQ mq = ResetIsvMchAppInfoConfigMQ
                .build(ResetIsvMchAppInfoConfigMQ.RESET_TYPE_MCH_APP, null, null, dbRecord.getInfoId());
        payMqSender.send(mq);
    }

    @Override
    public PayInterfaceConfig getByInfoIdAndIfCode(String infoType, String infoId, String ifCode) {
        PayInterfaceConfig dbRecord = getOne(PayInterfaceConfig.lqw()
                .eq(PayInterfaceConfig::getInfoType, infoType)
                .eq(PayInterfaceConfig::getInfoId, infoId)
                .eq(PayInterfaceConfig::getIfCode, ifCode)
        );
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (Objects.nonNull(dbRecord)) {
            AesCrypto aesCrypto = new AesCrypto(globalProperties.getSecretKey());
            String ifParams = aesCrypto.decrypt(dbRecord.getIfParams());
            dbRecord.setIfParams(ifParams);

            // 费率转换为百分比数值
            if (dbRecord.getIfRate() != null) {
                dbRecord.setIfRate(dbRecord.getIfRate().multiply(new BigDecimal("100")));
            }

            // 敏感数据脱敏
            if (StringUtils.isNotEmpty(ifParams)) {
                // TODO 待处理
//                MchInfo mchInfo = mchInfoManager.getById(userApp.getBelongInfoId());
                MchInfo mchInfo = new MchInfo();
                // 普通商户的支付参数执行数据脱敏
                if (Cs.MCH_TYPE_NORMAL.equals(mchInfo.getType())) {
                    NormalMchParams mchParams = AbstractPayFactory.getInstance(IfCodeEnum.ofByCode(dbRecord.getIfCode()))
                            .buildNormalMchParams(ifParams);
                    if (mchParams != null) {
                        dbRecord.setIfParams(mchParams.deSenData());
                    }
                }
            }
        }
        return dbRecord;
    }

    @Override
    @Transactional
    public void addPayIf(PayInterfaceRQ req) {
        MchApp mchApp = mchAppService.getMchAppById(req.getAppId());
        if (Objects.isNull(mchApp)) {
            throw new BizException("商户应用不存在");
        }
        req.getIfDefineIds().forEach(payIfDefineId -> {
            PayInterfaceDefine define = payInterfaceDefineManager.getById(payIfDefineId);
            if (Objects.isNull(define)) {
                return;
            }

            //根据 商户号、接口类型 获取商户参数配置
            PayInterfaceConfig dbRecord = this.getByInfoIdAndIfCode(Cs.INFO_TYPE_MCH_APP, req.getAppId(), define.getIfCode());

            PayInterfaceConfig config = new PayInterfaceConfig();
            config.setInfoType(Cs.INFO_TYPE_MCH_APP);
            config.setIfCode(define.getIfCode());
            config.setStatus(Cs.NO);
            config.setInfoId(req.getAppId());

            // 添加更新者信息
            LoginUser loginUser = SecurityUtils.getLoginUser();
            Long userId = loginUser.getUserId();
            String realName = loginUser.getUserName();
            config.setUpdatedUid(userId);
            config.setUpdatedBy(realName);
            config.setIfParams("");

            //若配置存在，为saveOrUpdate添加ID，第一次配置添加创建者
            if (Objects.nonNull(dbRecord)) {
                // 合并支付参数
//                config.setIfParams(Optional.ofNullable(StringKit.marge(dbRecord.getIfParams(), config.getIfParams())).orElse(""));
                config.setId(dbRecord.getId());
            } else {
                config.setCreatedUid(userId);
                config.setCreatedBy(realName);
            }
            boolean result = this.saveOrUpdate(config);
            if (!result) {
                throw new BizException("添加失败");
            }
        });
        // 推送修改消息
        ResetIsvMchAppInfoConfigMQ mq = ResetIsvMchAppInfoConfigMQ
                .build(ResetIsvMchAppInfoConfigMQ.RESET_TYPE_MCH_APP, null, mchApp.getMchNo(), mchApp.getId());
        payMqSender.send(mq);
    }

    @Override
    @Transactional
    public void deletePayIfConfig(String id) {
        PayInterfaceConfig config = this.getById(id);
        if (Objects.isNull(config)) {
            return;
        }

        MchApp mchApp = mchAppService.getMchAppById(config.getInfoId());
        if (Objects.isNull(mchApp)) {
            throw new BizException("商户应用不存在");
        }

        this.removeById(id);

        LambdaQueryWrapper<MchPayPassage> lqw = MchPayPassage.lqw()
                .eq(MchPayPassage::getAppId, mchApp.getId())
                .eq(MchPayPassage::getIfCode, config.getIfCode());
        mchPayPassageManager.remove(lqw);



        // 推送修改消息
        ResetIsvMchAppInfoConfigMQ mq = ResetIsvMchAppInfoConfigMQ
                .build(ResetIsvMchAppInfoConfigMQ.RESET_TYPE_MCH_APP, null, mchApp.getMchNo(), mchApp.getId());
        payMqSender.send(mq);
    }

    @Override
    public boolean mchAppHasAvailableIfCode(String appId, String ifCode) {
        return this.count(
                PayInterfaceConfig.lqw()
                        .eq(PayInterfaceConfig::getIfCode, ifCode)
                        .eq(PayInterfaceConfig::getStatus, Cs.YES)
                        .eq(PayInterfaceConfig::getInfoId, appId)
                        .eq(PayInterfaceConfig::getInfoType, Cs.INFO_TYPE_MCH_APP)
        ) > 0;
    }
}
